package cn.edu.sgu.www.mhxysy.service.chongwu_equipment.impl;

import cn.edu.sgu.www.mhxysy.dto.chongwu_equipment.ChongwuEquipmentAttributeDTO;
import cn.edu.sgu.www.mhxysy.entity.chongwu.Chongwu;
import cn.edu.sgu.www.mhxysy.entity.chongwu_equipment.*;
import cn.edu.sgu.www.mhxysy.entity.except.Property;
import cn.edu.sgu.www.mhxysy.enums.ChongwuEquipmentAttributeTypes;
import cn.edu.sgu.www.mhxysy.enums.PropertyTypes;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.mapper.chongwu.ChongwuMapper;
import cn.edu.sgu.www.mhxysy.mapper.chongwu_equipment.*;
import cn.edu.sgu.www.mhxysy.mapper.except.PropertyMapper;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.service.chongwu_equipment.ChongwuEquipmentAttributeService;
import cn.edu.sgu.www.mhxysy.vo.except.AttributeVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Service
public class ChongwuEquipmentAttributeServiceImpl implements ChongwuEquipmentAttributeService {

    private final ChongwuMapper chongwuMapper;
    private final PropertyMapper propertyMapper;
    private final ChongwuTaozhuangCategoryMapper chongwuTaozhuangCategoryMapper;
    private final ChongwuEquipmentMapper chongwuEquipmentMapper;
    private final ChongwuEquipmentCategoryMapper chongwuEquipmentCategoryMapper;
    private final ChongwuEquipmentAttributeMapper chongwuEquipmentAttributeMapper;
    private final ChongwuEquipmentViewAttributeMapper chongwuEquipmentViewAttributeMapper;

    @Autowired
    public ChongwuEquipmentAttributeServiceImpl(
            ChongwuMapper chongwuMapper,
            PropertyMapper propertyMapper,
            ChongwuTaozhuangCategoryMapper chongwuTaozhuangCategoryMapper,
            ChongwuEquipmentMapper chongwuEquipmentMapper,
            ChongwuEquipmentCategoryMapper chongwuEquipmentCategoryMapper,
            ChongwuEquipmentAttributeMapper chongwuEquipmentAttributeMapper,
            ChongwuEquipmentViewAttributeMapper chongwuEquipmentViewAttributeMapper) {
        this.chongwuMapper = chongwuMapper;
        this.propertyMapper = propertyMapper;
        this.chongwuTaozhuangCategoryMapper = chongwuTaozhuangCategoryMapper;
        this.chongwuEquipmentMapper = chongwuEquipmentMapper;
        this.chongwuEquipmentCategoryMapper = chongwuEquipmentCategoryMapper;
        this.chongwuEquipmentAttributeMapper = chongwuEquipmentAttributeMapper;
        this.chongwuEquipmentViewAttributeMapper = chongwuEquipmentViewAttributeMapper;
    }

    @Override
    public void insert(ChongwuEquipmentAttributeDTO chongwuEquipmentAttributeDTO) {
        // 验证属性是否重复
        QueryWrapper<ChongwuEquipmentAttribute> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("property_id", chongwuEquipmentAttributeDTO.getPropertyId());
        queryWrapper.eq("equipment_id", chongwuEquipmentAttributeDTO.getEquipmentId());

        // 通过 宠物装备ID、属性类型ID 查询宠物装备属性
        List<ChongwuEquipmentAttribute> list = chongwuEquipmentAttributeMapper.selectList(queryWrapper);

        if (!list.isEmpty()) {
            throw new GlobalException(ResponseCode.CONFLICT, "该宠物装备已经添加了相同的属性，添加失败~");
        }

        if (validateRange(chongwuEquipmentAttributeDTO)) {
            ChongwuEquipmentAttribute chongwuEquipmentAttribute = toEntity(chongwuEquipmentAttributeDTO);

            Integer propertyId = chongwuEquipmentAttribute.getPropertyId();

            Property property = propertyMapper.selectById(propertyId);

            chongwuEquipmentAttribute.setId(chongwuEquipmentAttribute.uuid());
            chongwuEquipmentAttribute.setType(property.getType());

            chongwuEquipmentAttributeMapper.insert(chongwuEquipmentAttribute);
        }
    }

    @Override
    public void deleteById(String id) {
        ChongwuEquipmentAttribute chongwuEquipmentAttribute = chongwuEquipmentAttributeMapper.selectById(id);
        Integer type = chongwuEquipmentAttribute.getType();

        if (ChongwuEquipmentAttributeTypes.JCSX.getValue().equals(type)) {
            throw new GlobalException(ResponseCode.FORBIDDEN, "宠物装备的基础属性不能删除。");
        }
        // 删除外观属性需要验证宠物穿戴的装备
        if (ChongwuEquipmentAttributeTypes.WGZJ.getValue().equals(type)) {
            // 得到宠物装备ID
            String equipmentId = chongwuEquipmentAttribute.getEquipmentId();
            // 查询宠物装备信息，得到宠物ID
            ChongwuEquipment chongwuEquipment = chongwuEquipmentMapper.selectById(equipmentId);
            String chongwuId = chongwuEquipment.getChongwuId();

            QueryWrapper<ChongwuEquipment> queryWrapper = new QueryWrapper<>();

            queryWrapper.eq("chongwu_id", chongwuId);

            List<ChongwuEquipment> list = chongwuEquipmentMapper.selectList(queryWrapper);

            // 如果宠物装备穿戴的件数为3
            if (list.size() == 3) {
                Chongwu chongwu = chongwuMapper.selectById(chongwuId);
                Integer categoryId = chongwu.getCategoryId();
                // 外观的出现次数
                int times = 0;

                for (ChongwuEquipment equipment : list) {
                    // 得到宠物装备的套装ID
                    Integer taozhuangId = equipment.getTaozhuangId();
                    ChongwuTaozhuangCategory chongwuTaozhuangCategory = chongwuTaozhuangCategoryMapper.selectById(taozhuangId);

                    // 套装匹配，并且存在外观，则times自增
                    if (categoryId.equals(chongwuTaozhuangCategory.getChongwuId()) && equipment.getWaiguanId() > 0) {
                        times ++;
                    }
                }

                // 三件外观装备激活外观效果
                if (times == 3) {
                    throw new GlobalException(ResponseCode.FORBIDDEN, "当前宠物穿戴了三件相同对应类型的外观装备，无法删除外观追加属性。");
                }
            }
        }

        chongwuEquipmentAttributeMapper.deleteById(id);
    }

    @Override
    public void updateById(ChongwuEquipmentAttributeDTO chongwuEquipmentAttributeDTO) {
        // 验证属性是否重复
        QueryWrapper<ChongwuEquipmentAttribute> queryWrapper = new QueryWrapper<>();

        queryWrapper.ne(
                chongwuEquipmentAttributeDTO.getId() != null,
                "id", chongwuEquipmentAttributeDTO.getId()
        );
        queryWrapper.eq("property_id", chongwuEquipmentAttributeDTO.getPropertyId());
        queryWrapper.eq("equipment_id", chongwuEquipmentAttributeDTO.getEquipmentId());

        List<ChongwuEquipmentAttribute> attributes = chongwuEquipmentAttributeMapper.selectList(queryWrapper);

        if (!attributes.isEmpty()) {
            throw new GlobalException(ResponseCode.CONFLICT, "该宠物装备已经添加了相同的属性，添加失败~");
        }

        if (validateRange(chongwuEquipmentAttributeDTO)) {
            ChongwuEquipmentAttribute chongwuEquipmentAttribute = toEntity(chongwuEquipmentAttributeDTO);

            chongwuEquipmentAttributeMapper.updateById(chongwuEquipmentAttribute);
        }
    }

    @Override
    public List<AttributeVO> selectAttributes(String equipmentId) {
        return chongwuEquipmentAttributeMapper.selectAttributes(equipmentId);
    }

    @Override
    public List<ChongwuEquipmentAttribute> selectByEquipmentId(String equipmentId) {
        QueryWrapper<ChongwuEquipmentAttribute> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("equipment_id", equipmentId);

        return chongwuEquipmentAttributeMapper.selectList(queryWrapper);
    }

    private ChongwuEquipmentAttribute toEntity(ChongwuEquipmentAttributeDTO chongwuEquipmentAttributeDTO) {
        ChongwuEquipmentAttribute chongwuEquipmentAttribute = new ChongwuEquipmentAttribute();
        
        chongwuEquipmentAttribute.setId(chongwuEquipmentAttributeDTO.getId());
        chongwuEquipmentAttribute.setEquipmentId(chongwuEquipmentAttributeDTO.getEquipmentId());
        chongwuEquipmentAttribute.setPropertyId(chongwuEquipmentAttributeDTO.getPropertyId());
        chongwuEquipmentAttribute.setPropertyValue(chongwuEquipmentAttributeDTO.getPropertyValue());
        
        return chongwuEquipmentAttribute;
    }

    /**
     * 验证属性范围是否合法
     * @param chongwuEquipmentAttributeDTO ChongwuEquipmentAttributeDTO
     * @return boolean
     */
    private boolean validateRange(ChongwuEquipmentAttributeDTO chongwuEquipmentAttributeDTO) {
        String equipmentId = chongwuEquipmentAttributeDTO.getEquipmentId();
        ChongwuEquipment chongwuEquipment = chongwuEquipmentMapper.selectById(equipmentId);
        ChongwuEquipmentCategory chongwuEquipmentCategory = chongwuEquipmentCategoryMapper.selectById(chongwuEquipment.getCategoryId());

        QueryWrapper<ChongwuEquipmentViewAttribute> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("equipment_id", chongwuEquipmentCategory.getType());
        queryWrapper.eq("grade", chongwuEquipmentCategory.getGrade());

        List<ChongwuEquipmentViewAttribute> viewAttributes = chongwuEquipmentViewAttributeMapper.selectList(queryWrapper);

        if (!viewAttributes.isEmpty()) {
            Map<String, Object> columnMap = new HashMap<>();

            columnMap.put("type", PropertyTypes.FJSX.getValue());

            List<Property> properties = propertyMapper.selectByMap(columnMap);

            // 附加属性跳过验证
            for (Property property : properties) {
                if (property.getId().equals(chongwuEquipmentAttributeDTO.getPropertyId())) {
                    return true;
                }
            }

            // 普通属性验证属性类型和范围
            for (ChongwuEquipmentViewAttribute viewAttribute : viewAttributes) {
                if (viewAttribute.getPropertyId().equals(chongwuEquipmentAttributeDTO.getPropertyId())) {
                    Integer min = viewAttribute.getMin();
                    Integer max = viewAttribute.getMax();

                    if (chongwuEquipmentAttributeDTO.getPropertyValue() > max || chongwuEquipmentAttributeDTO.getPropertyValue() < min) {
                        throw new GlobalException(ResponseCode.FORBIDDEN, "装备属性不合法，数值范围为："+ min + "~" + max);
                    }
                }
            }
        }

        return true;
    }

}